﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Tycho.Parser.Tokens;
using Tycho.Runtime;

namespace Tycho.Transactions {
    public class TransactionalRuntimeModule : IRuntimeModule {
        DefaultRuntimeModule RuntimeModule;

        public TransactionalRuntimeModule () {
            RuntimeModule = new DefaultRuntimeModule ();

            RuntimeModule.DynamicStackFrame = new TransactionalDynamicFrameObject (null);

            RuntimeModule.Null = new TransactionalObject (RuntimeModule.Null);
            RuntimeModule.Object = new TransactionalObject (RuntimeModule.Object);
            RuntimeModule.Integer = new TransactionalObject (RuntimeModule.Integer);
            RuntimeModule.Real = new TransactionalObject (RuntimeModule.Real);
            RuntimeModule.Boolean = new TransactionalObject (RuntimeModule.Boolean);
            RuntimeModule.String = new TransactionalObject (RuntimeModule.String);
            RuntimeModule.DateTime = new TransactionalObject (RuntimeModule.DateTime);
            RuntimeModule.Operation = new TransactionalObject (RuntimeModule.Operation);
            RuntimeModule.Closure = new TransactionalObject (RuntimeModule.Closure);
            RuntimeModule.Module = new TransactionalObject (RuntimeModule.Module);
            RuntimeModule.ModuleFrame = new TransactionalObject (RuntimeModule.ModuleFrame);
            RuntimeModule.Dictionary = new TransactionalObject (RuntimeModule.Dictionary);
            RuntimeModule.StackFrame = new TransactionalObject (RuntimeModule.StackFrame);
            RuntimeModule.List = new TransactionalObject (RuntimeModule.List, PrototypeReadOnlyMethods);
            RuntimeModule.Set = new TransactionalObject (RuntimeModule.Set);
            RuntimeModule.Structure = new TransactionalObject (RuntimeModule.Structure, PrototypeReadOnlyMethods);
            RuntimeModule.Symbol = new TransactionalObject (RuntimeModule.Symbol);
        }

        #region IRuntimeModule Members

        public AnyObject Integer {
            get { return RuntimeModule.Integer; }
        }

        public AnyObject Real {
            get { return RuntimeModule.Real; }
        }

        public AnyObject Boolean {
            get { return RuntimeModule.Boolean; }
        }

        public AnyObject String {
            get { return RuntimeModule.String; }
        }

        public AnyObject DateTime {
            get { return RuntimeModule.DateTime; }
        }

        public AnyObject Operation {
            get { return RuntimeModule.Operation; }
        }

        public AnyObject Closure {
            get { return RuntimeModule.Closure; }
        }

        public AnyObject Module {
            get { return RuntimeModule.Module; }
        }

        public AnyObject ModuleFrame {
            get { return RuntimeModule.ModuleFrame; }
        }

        public AnyObject Dictionary {
            get { return RuntimeModule.Dictionary; }
        }

        public AnyObject StackFrame {
            get { return RuntimeModule.StackFrame; }
        }

        public AnyObject DynamicStackFrame { get; private set; }

        public AnyObject List {
            get { return RuntimeModule.List; }
        }

        public AnyObject Set {
            get { return RuntimeModule.Set; }
        }

        public AnyObject Structure {
            get { return RuntimeModule.Structure; }
        }

        public AnyObject Object {
            get { return RuntimeModule.Object; }
        }

        public AnyObject Symbol {
            get { return RuntimeModule.Symbol; }
        }

        public AnyObject Constructor {
            get { return RuntimeModule.Constructor; }
        }

        public AnyObject Null {
            get { return RuntimeModule.Null; }
        }

        public AnyObject CreateInteger (int n) {
            return RuntimeModule.CreateInteger (n);
        }

        public AnyObject CreateReal (double n) {
            return RuntimeModule.CreateReal (n);
        }

        public AnyObject CreateBoolean (bool b) {
            return RuntimeModule.CreateBoolean (b);
        }

        public AnyObject CreateString (string s) {
            return RuntimeModule.CreateString (s);
        }

        public AnyObject CreateDateTime (DateTime d) {
            return RuntimeModule.CreateDateTime (d);
        }

        public AnyObject CreateStructure (params AnyObject [] fields) {
            return new TransactionalObject (RuntimeModule.CreateStructure (fields), new [] {Symbols.RuntimeGetProperty, Symbols.RuntimeProperties, Symbols.RuntimeObjectReferences, Symbols.RuntimeMethods});
        }

        public AnyObject CreateList (IEnumerable<AnyObject> items) {
            return new TransactionalObject (RuntimeModule.CreateList (items), PrototypeReadOnlyMethods);
        }

        public AnyObject CreateSet (IEnumerable<AnyObject> items) {
            return new TransactionalObject (RuntimeModule.CreateSet (items));
        }

        public AnyObject CreateDictionary (params AnyObject [] entries) {
            return new TransactionalObject (RuntimeModule.CreateDictionary (entries));
        }

        public AnyObject CreateClosure (ByteCode [] code, AnyObject [] constants, AnyObject parametersSchema, AnyObject context, SourceLocation sloc) {
            return RuntimeModule.CreateClosure (code, constants, parametersSchema, context, sloc);
        }

        public AnyObject CreateModule (Namespace ns) {
            return new TransactionalObject (RuntimeModule.CreateModule (ns));
        }

        static Symbol [] PrototypeReadOnlyMethods = new [] { Symbols.RuntimeGetProperty, Symbols.RuntimeProperties, Symbols.RuntimeObjectReferences, Symbols.RuntimeMethods, Symbols.RuntimeIndexGet };
        public AnyObject CreatePrototype () {
            return new TransactionalObject (RuntimeModule.CreatePrototype (), PrototypeReadOnlyMethods);
        }

        public AnyObject CreatePrototype (AnyObject parent) {
            return new TransactionalObject (RuntimeModule.CreatePrototype (parent), PrototypeReadOnlyMethods);
        }

        public AnyObject CreateNative<T> (T native) {
            return new TransactionalObject(RuntimeModule.CreateNative<T>(native));
        }

        public AnyObject CreateProtocol () {
            return new ProtocolObject ();
        }

        #endregion
    }
}
